// Copyright 2011, Vanya Davidenko.
// Используемая кодировка: UTF-8.

#ifndef LIBV_FILE_WINDOWS_REQUEST_COMPLETION_HANDLE_HPP_
#define LIBV_FILE_WINDOWS_REQUEST_COMPLETION_HANDLE_HPP_

#ifndef _WIN32
# error "This header should be used in Windows only."
#endif

#include <utility>
#include <libv/atomic.h>
#include <libv/static_assert.h>
#include <libv/stdint.h>
#include <libv/windows_lean.h>
#include <libv/acfile.h>



namespace libv
{

FileSlice ACFile::RequestCompletionHandle::RequestHandle2FileSilce(
    const RequestHandle& request_handle,
    const uint32_t num_bytes_to_transfer) const
{
    const fpos64 offset =
        ( static_cast<fpos64>(request_handle.OffsetHigh) << 32 ) +
        request_handle.Offset;

    return FileSlice(offset, num_bytes_to_transfer);
}



enum ACFile::RequestCompletionHandle::Status
    ACFile::RequestCompletionHandle::StatusImpl() const
{
    // Лучше пользоваться GetOverlappedResult, чем руками смотреть поля
    // структуры OVERLAPPED — в Windows7 у данной функции защита от гонок.
    DWORD num_of_bytes_transferred = 0;
    const bool r = ( ::GetOverlappedResult(file_handle_,
                                           request_handle_,
                                           &num_of_bytes_transferred,
                                           FALSE) != FALSE );
    last_error_ = ::GetLastError();

    if ( r && num_of_bytes_transferred == file_slice_.second )
        return COMPLETED;
    else if ( last_error_ == ERROR_IO_PENDING ||
              last_error_ == ERROR_IO_INCOMPLETE )
        return PENDING;
    else if ( last_error_ == ERROR_OPERATION_ABORTED )
        return CANCELED;
    else
        return FAILED;
}



bool ACFile::RequestCompletionHandle::WaitUntilFinishedImpl() const
{
    const bool result = ( ::WaitForSingleObject(
        request_handle_->hEvent, INFINITE) == WAIT_OBJECT_0 );
    last_error_ = ::GetLastError();

    return result;
}



void ACFile::RequestCompletionHandle::DestructImpl()
{
    ::CloseHandle(request_handle_->hEvent);
    request_handle_->hEvent = NULL;
}

}  // libv

#endif  // LIBV_FILE_WINDOWS_REQUEST_COMPLETION_HANDLE_HPP_
